﻿using System;
using System.Collections.Generic;
using System.Text;

using YouHP.Model;
using YouHP.DALFactory;

namespace YouHP.BLL
{
    public class DoctorBLL
    {
        #region 单件模式
        static DoctorBLL _Instance;

        public static DoctorBLL Instance
        {
            get
            {
                if (_Instance == null)
                {
                    _Instance = new DoctorBLL();
                }
                return _Instance;
            }
        }
        #endregion

        #region 中药医生的查询、添加、更新和删除

        public DoctorInfo GetDoctorInfo(int did)
        {
            return DataAccess.DoctorDAL.GetDoctorInfo(did);
        }

        public DoctorInfo GetDoctorInfoByNameHospital(string name, string hospital)
        {
            List<DoctorInfo> doctors = DataAccess.DoctorDAL.GetDoctorInfoByNameHospital(name, hospital);
            if (doctors != null && doctors.Count > 0)
                return doctors[0];
            return new DoctorInfo();
        }

        public int AddDoctorInfo(DoctorInfo info)
        {
            return DataAccess.DoctorDAL.AddDoctor(info);
        }

        public bool UpdateDoctorInfo(DoctorInfo info)
        {
            return DataAccess.DoctorDAL.UpdateDoctor(info);
        }

        public bool DeleteDoctorInfo(int did)
        {
            return DataAccess.DoctorDAL.DeleteDoctor(did);
        }

        #endregion

        #region 中药医生列表及其搜索

        public List<DoctorInfo> GetDoctorList(int pageSize, int pageIndex, string condStr, out int count)
        {
            return DataAccess.DoctorDAL.GetDoctorList(pageSize, pageIndex, condStr, out count);
        }

        public List<DoctorInfo> GetDoctorList(int pageSize, int pageIndex, string condStr, string orderStr, out int count)
        {
            return DataAccess.DoctorDAL.GetDoctorList(pageSize, pageIndex, condStr, orderStr, out count);
        }

        // Use refined SP.
        public List<DoctorInfo> GetDoctorListEx(int pageSize, int pageIndex, int diseaseId, out int count)
        {
            return DataAccess.DoctorDAL.GetDoctorListEx(pageSize, pageIndex, diseaseId, out count);
        }

        public List<DoctorInfo> GetDoctorList(string condStr)
        {
            return DataAccess.DoctorDAL.GetDoctorList(condStr);
        }

        #endregion

        // We will calculate how many patients use this prescription in this function.
        // This is an ugly implemenation, should be optimized later...
        public List<PrescriptionInfo> GetDoctorPrescriptionList(int did)
        {
            List<PrescriptionInfo> list = PrescriptionBLL.Instance.GetDoctorPrescriptionList(did);
            for (int idx = 0; idx < list.Count; ++idx)
            {
                int pid = list[idx].Id;

                list[idx].UserIds = PatientPrescriptionBLL.Instance.GetIdsOfUserWhoDosePrescription(pid);
                list[idx].UserCount = list[idx].UserIds.Count;
            }

            return list;
        }

        public int AddDoctor(string doctorName, string doctorHospital, int diseaseId)
        {
            DoctorInfo dInfoToAdd = new DoctorInfo();
            dInfoToAdd.Name                     = doctorName;
            dInfoToAdd.Hospital                 = doctorHospital;
            dInfoToAdd.IsFamous                 = false;
            dInfoToAdd.Description              = "";
            dInfoToAdd.PrescriptionCount        = 0;        // Will be incremented later.
            dInfoToAdd.PrescriptionAverageScore = 0.0;      // Will be updated later.
            dInfoToAdd.DiseaseId                = diseaseId;
            dInfoToAdd.CreateTime               = DateTime.Now;

            return DoctorBLL.Instance.AddDoctorInfo(dInfoToAdd);
        }

        // A doctor may own several prescriptions;
        // A prescription has a score, and this prescription may be the parent of other prescriptions, of each has a score.
        // The average prescription score of the doctor is computed by the formula:
        //  sum of all the prescriptions / count of users
        public bool UpdateDoctorPrescriptionAverageScoreAndCount(int doctorId)
        {
            DoctorInfo doctorInfo = GetDoctorInfo(doctorId);
            if (doctorInfo.Id <= 0)
                return false;

            List<PrescriptionInfo> allPrescriptions;
            string condStr = string.Format(@"[doctorid]={0}", doctorId);
            allPrescriptions = PrescriptionBLL.Instance.GetPrescriptionList(condStr);

            if (allPrescriptions == null || allPrescriptions.Count == 0)
                return false;

            double sumScore = 0.0;
            foreach (PrescriptionInfo pres in allPrescriptions)
            {
                sumScore += pres.Score;
            }

            int presCount = allPrescriptions.Count;
            double rawAverageScore = (double)sumScore / presCount;
            doctorInfo.PrescriptionAverageScore = Math.Round(rawAverageScore, 2, MidpointRounding.AwayFromZero);

            // CAUTION!!
            condStr = string.Format(@"[doctorid]={0} AND [parentId]=0", doctorId);
            List<PrescriptionInfo> uniquePrescriptions = PrescriptionBLL.Instance.GetPrescriptionList(condStr);
            doctorInfo.PrescriptionCount = uniquePrescriptions.Count;

            return UpdateDoctorInfo(doctorInfo);
        }   //UpdateDoctorPrescriptionAverageScore

        public bool UpdaetAllDoctorPrescritionAverageScoreAndCount()
        {
            int doctorCount = 0;
            List<DoctorInfo> allDoctors = GetDoctorList(10000, 1, "", out doctorCount);
            if (allDoctors == null || allDoctors.Count == 0)
                return false;

            bool allSucceeded = true;
            foreach (DoctorInfo doctorInfo in allDoctors)
            {
                if (!UpdateDoctorPrescriptionAverageScoreAndCount(doctorInfo.Id))
                {
                    allSucceeded = false;
                    continue;
                }
            }

            return allSucceeded;
        }   // UpdaetAllDoctorPrescritionAverageScore

        public bool hasClassicPrescription(int doctorId)
        {
            DoctorInfo doctorInfo = GetDoctorInfo(doctorId);
            if (doctorInfo.Id <= 0)
                return false;

            List<PrescriptionInfo> allPrescriptions;
            string condStr = string.Format(@"[doctorid]={0}", doctorId);
            allPrescriptions = PrescriptionBLL.Instance.GetPrescriptionList(condStr);

            if (allPrescriptions == null || allPrescriptions.Count == 0)
                return false;

            foreach (PrescriptionInfo pres in allPrescriptions)
            {
                if (pres.IsClassic)
                    return true;
            }

            return false;
        }
    }
}
